package cn.dengta.webapp.trade.dto;

import javax.annotation.Nullable;

import cn.dengta.common.context.I18N;
import cn.dengta.common.model.BizFlag;
import cn.dengta.common.model.Messager;
import cn.dengta.context.model.UserI18nKey;
import cn.dengta.webapp.user.entity.Relation;
import lombok.Getter;
import lombok.Setter;
import me.codeplayer.util.Assert;

@Getter
@Setter
public class RelationDTO implements BizFlag.WritableBizFlag {

	/** lowUserId 主动拉黑 highUserId */
	static final int flagLowBlock = 1,
	/** highUserId 主动拉黑 lowUserId */
	flagHighBlock = 1 << 1,
	/** lowUserId 主动关注 highUserId */
	flagLowFollow = 1 << 10,
	/** highUserId 主动关注 lowUserId */
	flagHighFollow = 1 << 11;

	static final long[][] globalActions = {
			new long[] { flagLowBlock, flagLowFollow },
			new long[] { flagHighBlock, flagHighFollow }
	};

	static final int blockIndex = 0, followIndex = 1;

	final Long lowUserId;
	final Long highUserId;

	long bizFlag;

	/** 【不可变】自己看自己 */
	public static final RelationDTO NONE = new RelationDTO(0L, 1L, 0);

	public RelationDTO(Long lowUserId, Long highUserId, long bizFlag) {
		this.lowUserId = lowUserId;
		this.highUserId = highUserId;
		Assert.isTrue(lowUserId < highUserId);
		this.bizFlag = bizFlag;
	}

	public static RelationDTO of(Long userId, Long toUserId, long score) {
		final boolean low = userId < toUserId;
		return new RelationDTO(low ? userId : toUserId, low ? toUserId : userId, score);
	}

	public static RelationDTO of(Relation t) {
		final Long toUserId = t.getToUserId();
		final RelationDTO dto = of(t.getUserId(), toUserId, 0);
		final Integer status = t.getStatus();
		if (Relation.RelationStatus.BIND.eq(status)) { // 关注
			dto.follow(toUserId, true);
		} else if (Relation.RelationStatus.BLOCK.eq(status)) { // 主动拉黑
			dto.block(toUserId, true);
		} else if (Relation.RelationStatus.TO_BLOCK.eq(status)) { // 被拉黑
			dto.block(t.getUserId(), true);
		}
		if (Relation.RelationStatus.BIND.eq(t.getToStatus())) { // 被关注
			dto.follow(t.getUserId(), true);
		}
		return dto;
	}

	@Nullable
	public Messager<String> follow(Long toUserId, boolean followOrCancel) {
		final boolean selfIsLow = toUserId.equals(highUserId);
		final long[] actions = globalActions[selfIsLow ? 0 : 1], toActions = globalActions[selfIsLow ? 1 : 0];
		if (followOrCancel) { // 关注
			final long bizFlag = this.bizFlag;
			if (BizFlag.hasFlag(bizFlag, toActions[blockIndex])) { // 已被对方拉黑
				return Messager.error(I18N.msg(UserI18nKey.STOP_OPERATION_FOR_BLOCKED));
			}
			if (BizFlag.hasFlag(bizFlag, actions[blockIndex])) { // 已拉黑对方
				return Messager.error(I18N.msg(UserI18nKey.STOP_OPERATION_FOR_BLOCK));
			}
			if (BizFlag.hasFlag(bizFlag, actions[followIndex])) { // 已关注
				return Messager.error(I18N.msg(UserI18nKey.FOLLOW_COLLECT_ADD_OPERATION_STATUS_ERROR));
			}
			// 关注的同时自动取消自己的主动拉黑
			this.bizFlag = bizFlag & ~actions[blockIndex] | actions[followIndex];
		} else { // 取消关注
			if (!BizFlag.hasFlag(bizFlag, actions[followIndex])) { // 尚未关注
				return Messager.error(I18N.msg(UserI18nKey.FOLLOW_COLLECT_CANCEL_OPERATION_STATUS_ERROR));
			}
			removeFlag(actions[followIndex]);
		}
		return null;
	}

	@Nullable
	public Messager<String> block(Long toUserId, boolean blockOrCancel) {
		final boolean selfIsLow = toUserId.equals(highUserId);
		final long[] actions = globalActions[selfIsLow ? 0 : 1], toActions = globalActions[selfIsLow ? 1 : 0];
		if (blockOrCancel) { // 拉黑
			final long bizFlag = this.bizFlag;
			if (BizFlag.hasFlag(bizFlag, actions[blockIndex])) { // 已拉黑对方
				return Messager.error(I18N.msg(UserI18nKey.STOP_OPERATION_FOR_BLOCK));
			}
			if (BizFlag.hasFlag(bizFlag, toActions[blockIndex])) { // 已被对方拉黑（暂不支持双向互相拉黑）
				return Messager.error(I18N.msg(UserI18nKey.STOP_OPERATION_FOR_BLOCKED));
			}
			// 拉黑的同时会自动双向取消关注
			this.bizFlag = bizFlag & ~actions[followIndex] & ~toActions[followIndex] | actions[blockIndex];
		} else { // 取消拉黑
			if (!BizFlag.hasFlag(bizFlag, actions[blockIndex])) { // 尚未拉黑
				return Messager.error(I18N.msg(UserI18nKey.FOLLOW_BLOCK_CANCEL_OPERATION_STATUS_ERROR));
			}
			removeFlag(actions[blockIndex]);
		}
		return null;
	}

	/**
	 * 是否是【好友】关系（互相关注）
	 */
	public boolean isFriend() {
		return BizFlag.hasFlag(bizFlag, globalActions[0][followIndex] | globalActions[1][followIndex]);
	}

	/**
	 * 是否是【拉黑】关系（有任意一方拉黑就算）
	 */
	public boolean isAnyBlock() {
		return hasAnyFlag(globalActions[0][blockIndex], globalActions[1][blockIndex]);
	}

	/**
	 * 是否已关注对方
	 */
	public boolean isFollowed(Long toUserId) {
		final boolean selfIsLow = toUserId.equals(highUserId);
		final long[] actions = globalActions[selfIsLow ? 0 : 1];
		return BizFlag.hasFlag(bizFlag, actions[followIndex]);
	}

	/** 是否主动拉黑对方 */
	public boolean isBlock(Long toUserId) {
		final boolean selfIsLow = toUserId.equals(highUserId);
		final long[] actions = globalActions[selfIsLow ? 0 : 1];
		return BizFlag.hasFlag(bizFlag, actions[blockIndex]);
	}

	/** 是否被对方拉黑 */
	public boolean isToBlock(Long toUserId) {
		final boolean selfIsLow = toUserId.equals(highUserId);
		final long[] toActions = globalActions[selfIsLow ? 1 : 0];
		return BizFlag.hasFlag(bizFlag, toActions[blockIndex]);
	}

}
